// 12.3.5 模板实参的等价性
// 模板实参的等价性（Template Argument Equivalence）是指确定两组模板实参是否应该导致相同模板实例化的规则。这些规则对于理解模板实例化、特化选择和链接时的符号解析至关重要。

// 基本原则
// 两组模板实参被认为是等价的，如果它们在以下方面相同：
// 1.数量：参数数量必须相同
// 2.种类：对应位置的参数必须是相同种类（类型、非类型或模板）
// 3.值：对应位置的参数必须有等价的值

// 类型实参的等价性
// 类型实参的等价性基于类型的等价性规则：
template <typename T>
class Example
{
};

// 这些是相同的模板实例
Example<int> a;
Example<int> b;

// typedef不影响类型等价性
typedef int Integer;
Example<Integer> c; // 与Example<int>相同

// cv限定符会影响类型等价性
Example<const int> d; // 与Example<int>不同

// 非类型实参的等价性
// 非类型实参的等价性基于它们的值和表示方式：
template <int N>
class IntConstant
{
};

// 这些是相同的模板实例
IntConstant<42> a;
IntConstant<40 + 2> b;
const int c = 42;
IntConstant<c> d;

// 但这些是不同的实例
template <const char *Str>
class StringConstant
{
};

extern const char str1[] = "hello";
extern const char str2[] = "hello";
StringConstant<str1> s1;
StringConstant<str2> s2; // 与s1不同，因为指向不同的地址

// 模板模板实参的等价性
// 模板模板实参的等价性基于模板的定义：
template <template <typename> class T>
class TemplateWrapper
{
};

template <typename T>
class Container1
{
};

template <typename T>
class Container2
{
};

// 这些是不同的模板实例
TemplateWrapper<Container1> a;
TemplateWrapper<Container2> b; // 与a不同，因为Container1和Container2是不同的模板

// 但这些是相同的实例
template <typename T>
using Alias = Container1<T>;
TemplateWrapper<Container1> c;
TemplateWrapper<Alias> d; // 与c相同，因为Alias是Container1的别名

// 实参等价性与链接
// 1.模板实参的等价性直接影响链接时的符号解析：
// 在文件1中
template <int N>
void function() { /*...*/ }
function<42>(); // 实例化function<42>

// 在文件2中
template <int N>
void function() { /*...*/ }
const int answer = 42;
function<answer>(); // 使用相同的function<42>实例
// 编译器和链接器会根据模板实参的等价性规则，确定这两个调用应该使用同一个函数实例。

// 2.实参等价性与模板特化
// 模板特化的选择也依赖于实参等价性：
// 主模板
template <typename T>
class Traits
{
    static constexpr bool value = false;
};

// 特化
template <>
class Traits<int>
{
    static constexpr bool value = true;
};

// 使用typedef
typedef int Integer;
bool b = Traits<Integer>::value; // true，因为Integer等价于int